﻿using System;
using System.Collections.Generic;
using System.IO;
using Abp.Collections.Extensions;
using Abp.Localization;
using Castle.Core.Internal;
using Magicodes.ExcelExporter.Attributes;
using Magicodes.ExcelExporter.Models;
using Magicodes.Plus.Application.Dto;
using Magicodes.Plus.Core;
using OfficeOpenXml;
using OfficeOpenXml.Table;

namespace Magicodes.ExcelExporter
{
    public class ExcelExporter : IExcelExporter
    {
        private readonly ILocalizationManager _localizationManager;

        public ExcelExporter(ILocalizationManager localizationManager)
        {
            _localizationManager = localizationManager;
        }

        public IAppFolders AppFolders { get; set; }

        /// <summary>
        ///     导出Excel
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="dataItems">数据列</param>
        /// <returns>文件</returns>
        public FileDto Export<T>(string fileName, IList<T> dataItems)
        {
            var excelFileName = fileName + ".xlsx";
            return CreateExcelPackage(excelFileName, excelPackage =>
            {
                var sheet = excelPackage.Workbook.Worksheets.Add(fileName);
                sheet.OutLineApplyStyle = true;
                var exporterTableDto = GetExporterTableDto<T>();
                List<ExporterHeaderDto> exporterHeaderDtoList;
                if (GetExporterHeaderDtoList<T>(out exporterHeaderDtoList)) return;
                AddObjects(sheet, 1, dataItems);
                AddHeader(exporterHeaderDtoList, sheet, exporterTableDto);
                AddStyle(exporterHeaderDtoList, sheet);
            });
        }

        /// <summary>
        ///     创建Excel页
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="creator"></param>
        /// <returns></returns>
        protected FileDto CreateExcelPackage(string fileName, Action<ExcelPackage> creator)
        {
            var file = new FileDto(fileName, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

            using (var excelPackage = new ExcelPackage())
            {
                creator(excelPackage);
                Save(excelPackage, file);
            }
            return file;
        }

        /// <summary>
        ///     创建表头
        /// </summary>
        /// <param name="exporterHeaderDtoList"></param>
        /// <param name="sheet"></param>
        /// <param name="exporterTableDto"></param>
        protected void AddHeader(List<ExporterHeaderDto> exporterHeaderDtoList, ExcelWorksheet sheet, ExporterTableDto exporterTableDto)
        {
            if (exporterTableDto.LocalizationSource != null)
            {
                foreach (var exporterHeaderDto in exporterHeaderDtoList)
                {
                    if (exporterHeaderDto != null && exporterHeaderDto.Attribute.Length > 0)
                    {
                        var exporterHeaderAttribute = exporterHeaderDto.Attribute[0];
                        if (exporterHeaderAttribute != null)
                        {

                            sheet.Cells[1, exporterHeaderDto.Index].Value =
                                _localizationManager.GetString(exporterTableDto.LocalizationSource,
                                    exporterHeaderAttribute.DisplayName.IsNullOrEmpty()
                                        ? exporterHeaderDto.PropertyName
                                        : exporterHeaderAttribute.DisplayName);
                            sheet.Cells[1, exporterHeaderDto.Index].Style.Font.Bold = exporterHeaderAttribute.IsBold;
                            sheet.Cells[1, exporterHeaderDto.Index].Style.Font.Size = exporterHeaderAttribute.FontSize;
                        }
                    }
                }
            }
            else
            {
                foreach (var exporterHeaderDto in exporterHeaderDtoList)
                {
                    if (exporterHeaderDto != null && exporterHeaderDto.Attribute.Length > 0)
                    {
                        var exporterHeaderAttribute = exporterHeaderDto.Attribute[0];
                        if (exporterHeaderDto.Attribute[0] != null)
                        {

                            sheet.Cells[1, exporterHeaderDto.Index].Value =
                                exporterHeaderAttribute.DisplayName.IsNullOrEmpty()
                                    ? exporterHeaderDto.PropertyName
                                    : exporterHeaderAttribute.DisplayName;
                            sheet.Cells[1, exporterHeaderDto.Index].Style.Font.Bold = exporterHeaderAttribute.IsBold;
                            sheet.Cells[1, exporterHeaderDto.Index].Style.Font.Size = exporterHeaderAttribute.FontSize;
                        }
                    }
                }
            }
        }

        /// <summary>
        ///     添加导出数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sheet"></param>
        /// <param name="startRowIndex"></param>
        /// <param name="items"></param>
        protected void AddObjects<T>(ExcelWorksheet sheet, int startRowIndex, IList<T> items)
        {
            if (items.IsNullOrEmpty())
                return;
            sheet.Cells["A" + startRowIndex].LoadFromCollection(items, true, TableStyles.Medium10);
        }

        /// <summary>
        ///     添加样式
        /// </summary>
        /// <param name="exporterHeaderDtos"></param>
        /// <param name="sheet"></param>
        protected void AddStyle(List<ExporterHeaderDto> exporterHeaderDtos, ExcelWorksheet sheet)
        {
            foreach (var exporterHeaderDto in exporterHeaderDtos)
            {
                if (exporterHeaderDto.Attribute.Length > 0)
                {
                    var exporterHeaderAttribute = exporterHeaderDto.Attribute[0];
                    if (exporterHeaderAttribute != null)
                    {
                        sheet.Column(exporterHeaderDto.Index).Style.Numberformat.Format = exporterHeaderAttribute.Format;
                        if (exporterHeaderAttribute.IsAutoFit)
                            sheet.Column(exporterHeaderDto.Index).AutoFit();
                    }
                }
            }
        }

        /// <summary>
        ///     保存
        /// </summary>
        /// <param name="excelPackage"></param>
        /// <param name="file"></param>
        protected void Save(ExcelPackage excelPackage, FileDto file)
        {
            var filePath = Path.Combine(AppFolders.TempFileDownloadFolder, file.FileToken);
            excelPackage.SaveAs(new FileInfo(filePath));
        }

        private static bool GetExporterHeaderDtoList<T>(out List<ExporterHeaderDto> exporterHeaderDtoList)
        {
            exporterHeaderDtoList = new List<ExporterHeaderDto>();
            var objProperties = typeof(T).GetProperties();
            if (objProperties.IsNullOrEmpty())
                return true;
            for (var i = 0; i < objProperties.Length; i++)
            {
                exporterHeaderDtoList.Add(new ExporterHeaderDto
                {
                    Index = i + 1,
                    PropertyName = objProperties[i].Name,
                    Attribute = objProperties[i].GetCustomAttributes(typeof(ExporterHeaderAttribute), true) as ExporterHeaderAttribute[]
                });
            }
            return false;
        }

        private static ExporterTableDto GetExporterTableDto<T>()
        {
            var exporterTableDto = new ExporterTableDto();
            var exporterTableAttributes = typeof(T).GetCustomAttributes(typeof(ExporterTableAttribute), true);
            foreach (ExporterTableAttribute exporterTableAttribute in exporterTableAttributes)
            {
                if (exporterTableAttribute != null)
                {
                    exporterTableDto.LocalizationSource = exporterTableAttribute.LocalizationSource;
                    break;
                }
            }
            return exporterTableDto;
        }
    }
}